﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WpfRcp.Core.Services;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.Composite.Logging;

namespace WpfRcp.Logging.EnterpriseLibrary
{
    public class EntLibLoggerService : ILoggerService
    {
        public void Log(string message, string category, TraceEventType traceEventType, string title)
        {
            Logger.Write(message, category, 1, 1, traceEventType, title);
        }

        public void Log(string message, Category severity, Priority priority)
        {
            var category = "General";
            if (severity == Category.Debug)
                category = "Debug";
            else if (severity == Category.Exception)
                category = "Error";

            DoLog(message, category, ParseSeverity(severity), ParsePriority(priority), 2);
        }

        private void DoLog(string message, string category, TraceEventType severity, int priority, int frameNumber)
        {
            var entry = new LogEntry();
            entry.Severity = severity;
            entry.Priority = priority;
            entry.Message = message;
            entry.Categories.Add(category);

            IDictionary<string, object> extendedProperties = new Dictionary<string, object>();
            StackFrame frame = new StackTrace().GetFrame(frameNumber);
            string className = frame.GetMethod().DeclaringType.FullName;
            string methodName = frame.GetMethod().Name;

            extendedProperties.Add("Class Name", className ?? "Unknown");
            extendedProperties.Add("Method Name", methodName ?? "Unknown");

            entry.ExtendedProperties = extendedProperties;
            Logger.Write(entry);
        }

        private static TraceEventType ParseSeverity(Category category)
        {
            switch (category)
            {
                case Category.Debug:
                    return TraceEventType.Verbose;

                case Category.Exception:
                    return TraceEventType.Error;

                case Category.Info:
                    return TraceEventType.Information;

                case Category.Warn:
                    return TraceEventType.Warning;
            }

            throw new Exception("Should never happen.");
        }

        private static int ParsePriority(Priority priority)
        {
            int finalPriority;

            switch (priority)
            {
                case Priority.High:
                    finalPriority = 20;
                    break;

                case Priority.Medium:
                    finalPriority = 15;
                    break;

                case Priority.Low:
                    finalPriority = 10;
                    break;

                case Priority.None:
                    finalPriority = 1;
                    break;

                default:
                    throw new ArgumentOutOfRangeException("priority", priority, "Invalid priority.");
            }

            return finalPriority;
        }

        private static string ParseCategory(Category category)
        {
            return category.ToString();
        }
    }
}
